﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using LowLevelGraphics.ColorSpaces;
using LowLevelGraphics.Types.Interval;

namespace LowLevelGraphics.Filter.Colors
{
    /// <summary>
    /// The filter does color channels' filtering by clearing (filling with specified values) values,
    /// which are inside/outside of the specified value's range. 
    /// The filter allows to fill certain ranges of RGB color channels with specified value.
    /// The filter is similar to ColorFiltering, but operates with not entire pixels, 
    /// but with their RGB values individually. 
    /// This means that pixel itself may not be filtered (will be kept), 
    /// but one of its channels values may be filtered if they are inside/outside of specified range.
    /// The filter accepts 24 and 32 bpp color images for processing.
    /// </summary>
    public class ChannelFilter : BaseImageFilter
    {
        /// <summary>
        /// 
        /// </summary>
        protected DoubleInterval m_R = new DoubleInterval(0, 255);

        /// <summary>
        /// 
        /// </summary>
        protected DoubleInterval m_G = new DoubleInterval(0, 125);

        /// <summary>
        /// 
        /// </summary>
        protected DoubleInterval m_B = new DoubleInterval(0, 137);

        /// <summary>
        /// 
        /// </summary>
        protected AbstractColorSpace m_AbstractColorSpace = new NormalizedRGB(Definitions.White);

        /// <summary>
        /// Initializes a new instance of the <see cref="ChannelFilter"/> class.
        /// </summary>
        public ChannelFilter()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ChannelFilter"/> class.
        /// </summary>
        /// <param name="_channelFilter">The _channel filter.</param>
        internal ChannelFilter(ChannelFilter _channelFilter)
        {
            m_AbstractColorSpace = _channelFilter.m_AbstractColorSpace;
            m_B = _channelFilter.m_B;
            m_R = _channelFilter.m_R;
            m_G = _channelFilter.m_G;            
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int nWidth = _bitmap.Width;
            int nHeight = _bitmap.Height;

            int x = 0;
            int y = 0;

            for (y = 0; y < nWidth; y++)
            {
                for (x = 0; x < nHeight; x++)
                {
                    m_AbstractColorSpace.Color = _bitmap[x, y];
                    object[] aObject = m_AbstractColorSpace.GetValues();
                    double d1 = (double)aObject[0];
                    double d2 = (double)aObject[1];
                    double d3 = (double)aObject[2];

                    if (!m_R.Contains(d1))
                    {
                        aObject[0] = 0;
                    }
                    if (!m_G.Contains(d2))
                    {
                        aObject[1] = 0;
                    }
                    if (!m_B.Contains(d3))
                    {
                        aObject[2] = 0;
                    }
                    m_AbstractColorSpace.SetValues(aObject);
                    _bitmap[x, y] = m_AbstractColorSpace.ToColor();
                }
            }
            return base.Execute(_bitmap);
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ChannelFilter(this);
        }

        /// <summary>
        /// Gets or sets the color space.
        /// </summary>
        /// <value>The color space.</value>
        public AbstractColorSpace ColorSpace
        {
            get { return m_AbstractColorSpace; }
            set { m_AbstractColorSpace = value; }
        }

        /// <summary>
        /// Gets or sets the R.
        /// </summary>
        /// <value>The R.</value>
        public DoubleInterval R
        {
            get { return m_R; }
            set { m_R = value; }
        }

        /// <summary>
        /// Gets or sets the G.
        /// </summary>
        /// <value>The G.</value>
        public DoubleInterval G
        {
            get { return m_G; }
            set { m_G = value; }
        }

        /// <summary>
        /// Gets or sets the B.
        /// </summary>
        /// <value>The B.</value>
        public DoubleInterval B
        {
            get { return m_B; }
            set { m_B = value; }
        }
    }
}
